#include "InsertCommand.h"
#include <boost\tokenizer.hpp>
#include "VarcharCell.h"
#include "IntCell.h"
#include "NullCell.h"
#include <iostream>
using namespace boost;
using std::cout;

InsertCommand::InsertCommand(SQLSystem* sql): Command(sql) 
{
}


InsertCommand::~InsertCommand()
{
}

//INSERT INTO TABLENAME VALUES(...)
//INSERT INTO TABLENAME(COLUMN1, COLUMN2,...) VALUES(...)
int InsertCommand::execute(string str)
{
	vector<string> columnsToInsert;	//determines the columns to insert to the table
	vector<string> valuesToInsert;	//determines the values to insert to the table
	// the size of the two vector must be equal
	int numColumns, numValues;
	Table* table;
	SQLSystem* system;
	system= getSystem();
	typedef tokenizer<char_separator<char>> token;
	char_separator<char> sep(" ","(),",drop_empty_tokens);
	token tok(str, sep);
	token::iterator tok_iter= tok.begin();
	++tok_iter;
	if(tok_iter == tok.end())	
		return false;
	if(helper->toUpperString(*tok_iter)!="INTO")
	{
		cout << "WRONG FORMAT" <<endl;
		return false;
	}
	++tok_iter;
	if(tok_iter == tok.end())	
		return false;
	//table name
	if(tok_iter!=tok.end())
	{
		string tableName=*tok_iter;
		table= system->getTableByName(tableName);
		
	}
	else
		return false;
	if(table == NULL)
		return false;
	++tok_iter;
	if(tok_iter == tok.end())	
		return false;
	if(helper->toUpperString(*tok_iter) == "VALUES")
	{
		columnsToInsert= table->getColumns();
		numColumns= columnsToInsert.size();
	}
	else if(*tok_iter=="(")
	{
		++tok_iter;
		if(tok_iter == tok.end())	
			return false;
		while(*tok_iter!=")")
		{
			if(*tok_iter == ",")
			{
				++tok_iter;
				continue;
			}
			columnsToInsert.push_back(*tok_iter);
			++tok_iter;
		}
		numColumns= columnsToInsert.size();
	}
	else
	{
		cout << "SYNTAX ERROR" <<endl;
		return false;
	}	
	++tok_iter;
	if(tok_iter == tok.end())	
		return false;
	if(helper->toUpperString(*tok_iter) == "VALUES")
		++tok_iter;
	//either format of insert all leads to this parenthese if user enters correct format
	if(*tok_iter == "(")
		++tok_iter;
	else
		return false;
	while(*tok_iter!=")")
	{
		if(*tok_iter == ",")
		{
			++tok_iter;
			continue;
		}
		//check for a string data that begin with a double quote
		//insert a string field contains more than one words
		if((*tok_iter)[0] == '\"')
		{
			string vString;	//this new string contains the real data without the double quote
			unsigned int i=1;
			while((*tok_iter)[i] !='\"')	//to add "tien phat" we need to merge the two token "tien and phat"
			{
				vString +=(*tok_iter)[i];	//when i point at the end of token i= token's size-1 so if we let the condition in if with > then double 
				++i;						//space will be added
				if(i >= (*tok_iter).size())
				{
					vString += " "; //add space between two words
					++tok_iter;	//next token to continue merging the string
					i=0;	//set i=0 so in the while condition we check again from the start. when comes to the closing quote i= token's size-1 therefore
							//the while continue and check for condition and fail
					continue;
				}
			}
			valuesToInsert.push_back(vString);	//add the string data to the vector
		}
		//otherwise it's just an int value so we store it directly to the vector
		else
			valuesToInsert.push_back(*tok_iter);
		++tok_iter;
	}
	numValues= valuesToInsert.size();
	if(numColumns!=numValues)
	{
		cout << "Number of columns must equal number of values" << endl;
		return false;
	}

	//call insert method to insert the valuesToInsert from columns columnsToInsert to table
	insert(columnsToInsert, valuesToInsert, table);
	return true;
}


int InsertCommand::insert(vector<string> columns, vector<string> values, Table* p_table)
{
	Row* newRow= new Row;
	vector<string> columnsToInsert, valuesToInsert;
	columnsToInsert= columns;
	valuesToInsert= values;
	Table* table= p_table;	
	SQLSystem* system= getSystem();
	vector<string> allColumns= table->getColumns();
	vector<int> types= table->getTypes();
	if(allColumns.size() == columnsToInsert.size())
	{
		for(unsigned int i=0;i<valuesToInsert.size();i++)
		{
			int type= types[i];
			if(type == VARCHAR)
			{
				VarcharCell* cell= new VarcharCell;
				cell->setData(valuesToInsert[i]);
				newRow->addCell(cell);
			}
			else if(type == INT)
			{
				IntCell* cell= new IntCell;
				int data= helper->StringtoInt(valuesToInsert[i]);
				if(data == 0)
					return false;
				cell->setData(data);
				newRow->addCell(cell);
			}
		}
		table->addRow(newRow);
		//table->display();
		cout << "ROW SUCESSFULLY INSERTED.\n";
		return true;
	}
	else
	{
		int index, position=0;
		for(unsigned int i=0;i<valuesToInsert.size();i++)
		{
			index= table->getColumnIndex(columnsToInsert[i]);
			if(index == -1)
			{
				cout << "Wrong column name\n";
				cout << columnsToInsert[i] <<endl;
				return false;
			}
			for(int j=position;j<=index;j++)
			{
				if(j == index)
				{
					int type= types[index];
					if(type == VARCHAR)
					{
						VarcharCell* cell= new VarcharCell;
						cell->setData(valuesToInsert[i]);
						newRow->addCell(cell);
					}
					else if(type == INT)
					{
						IntCell* cell= new IntCell;
						int data= helper->StringtoInt(valuesToInsert[i]);
						if(data == 0)
							return false;
						cell->setData(data);
						newRow->addCell(cell);
					}
					
				}
				else
				{
					NullCell* cell= new NullCell;
					newRow->addCell(cell);
				}
				
			}
			position=index+1;
		}

		//check if the last column to insert is not the last column in the table, so we still have to fill in null cells
		if(index<allColumns.size()-1)
		{
			for(unsigned int i=index+1;i<allColumns.size();i++)
			{
				NullCell* cell= new NullCell;
				newRow->addCell(cell);
			}
		}
		table->addRow(newRow);	//add newRow to the table. newRow is a dynamically object in the freestore
		//table->display();
		cout << "ROW SUCESSFULLY INSERTED.\n";
		return true;
	
	}

}
